IN   -
OUT  Util
Type Memory
Ver  1.00f
Max  16k

#REM OFF
.limitstring
; > r0=string to process
;   r1=maximum size in scr units
; < r2=left characters to print
   STMFD   (sp)!,{r0-r1,r3-r8,link}
   MOV     r2,#0                      ; mid$ value
   MOV     r3,#0                      ; lastchar
   MOV     r5,#0                      ; length of last group (scr)
   MOV     r6,#0                      ; end of last group (len)
   MOV     r8,#0                      ; end of last string to fit
._ls_loop
   LDRB    r4,[r0,r2]                 ; mid$(r0,r2,1)
   REM     "Read %r4"
   CMP     r4,#ASC("A")               ;
   BLT     _ls_notcapital             ; jump if this<A
   CMP     r4,#ASC("Z")               ;
   BGT     _ls_notcapital             ; jump if this>Z
   CMP     r3,#ASC("a")               ;
   BLT     _ls_lastnotlower           ; jump if last<a
   CMP     r3,#ASC("z")               ;
   BGT     _ls_lastnotlower           ; jump if last>z
   BEQ     _ls_issplit                ; if [a-z][A-Z] then split
._ls_notcapital
   CMP     r4,#ASC("a")               ;
   BLT     _ls_notalpha               ; jump if this<a
   CMP     r4,#ASC("z")               ;
   BGT     _ls_notalpha               ; jump if this>z
._ls_lastnotupper
._ls_nextnotlower
   B       _ls_nosplit                ; if [a-zA-Z] then no split
._ls_lastnotlower
; check for [A-Z][A-Z][a-z]
   CMP     r3,#ASC("A")               ;
   BLT     _ls_lastnotupper           ; jump if last<A
   CMP     r3,#ASC("Z")               ;
   BGT     _ls_lastnotupper           ; jump if last>Z
   ADD     r2,r2,#1                   ;
   LDRB    r14,[r0,r2]                ; mid$(r0,r2+1,1)
   SUB     r2,r2,#1                   ; restore r2
   CMP     r14,#ASC("a")              ;
   BLT     _ls_nextnotlower           ; jump if next<a
   CMP     r14,#ASC("z")              ;
   BGT     _ls_nextnotlower           ; jump if next>z
   B       _ls_issplit                ; if [A-Z][A-Z][a-z] then no split

._ls_notalpha
   REM     "Not a letter"
   CMP     r4,#ASC("'")
   BEQ     _ls_nosplit                ; if ' then no split
._ls_issplit
   BL      _ls_lengthto
   CMP     r7,r1                      ; compare string length to max
   BGT     _ls_toolong                ; if too long jump
   MOV     r5,r7                      ; line len = r7
   MOV     r6,r2                      ; charmax = r6
   REM     "Marking line break at %r6"
   CMP     r4,#32                     ; is this end of line ?
   BLT     _ls_endofline

._ls_nosplit
   CMP     r6,#0                      ; have we found a break yet ?
   BNE     _ls_breakfound             ; if so skip
   BL      _ls_lengthto               ; if not find length of line
   CMP     r7,r1                      ;
   MOVLE   r8,r2                      ; r8=length of line
._ls_breakfound
   MOV     r3,r4                      ; r3=last character
   ADD     r2,r2,#1                   ; increment index
   B       _ls_loop

._ls_toolong
   REM     "line is too long, exiting"
   MOV     r2,r6
   CMP     r6,#0
   MOVEQ   r2,r8
._ls_endofline
   LDMFD   (sp)!,{r0-r1,r3-r8,pc}

._ls_lengthto
; find length of string up to
; > r0=string
;   r2=length to take
;   r4=character last read
; < r7=length in scr units
   STMFD   (sp)!,{r0-r5,link}
   CMP     r4,#32
   SUBLT   r2,r2,#1          ; if end of string then shorten
   MOV     r7,r2,LSL #4      ; temporary, chars*16 (as in system font)
   LDMFD   (sp)!,{r0-r5,pc}^ ; ...and restore flags

.callcode
   STMFD   (sp)!,{r0-r5,link}
   BL      limitstring
   STR     r2,`chars
   LDMFD   (sp)!,{r0-r5,pc}

.`chars
   EQUD    0

# POST
DIM a% 256
$a%="MyGrandma'sCertificate for thursday"
FOR len=0 TO LEN($a%)
 A%=a%:B%=16*len
 CALL callcode
 *|P."# chars = ";!`chars
 P."Line is :";LEFT$($a%,!`chars);":"
N.
